/*
============================================================================
 Name        : jsoncx.h
 Author      : moheng
 Version     : 1.0.0
 Copyright   :
 Description : jsoncx Head File
============================================================================
*/

#ifndef __JSONCX_H__
#define __JSONCX_H__

#ifdef __cplusplus
extern "C"
{
#endif
#include <stdio.h>

/* jsoncx types: */
#define jsoncx_false 0
#define jsoncx_true 1
#define jsoncx_null 2
#define jsoncx_number 3
#define jsoncx_string 4
#define jsoncx_array 5
#define jsoncx_object 6

#define jsoncx_isreference 256
#define jsoncx_stringisconst 512

    /* the jsoncx structure: */
    typedef struct jsoncx
    {
        struct jsoncx *next, *prev; /* next/prev allow you to walk array/object chains. alternatively, use getarraysize/getarrayitem/getobjectitem */
        struct jsoncx *child;       /* an array or object item will have a child pointer pointing to a chain of the items in the array/object. */

        int type; /* the type of the item, as above. */

        char *valuestring;  /* the item's string, if type==jsoncx_string */
        int valueint;       /* the item's number, if type==jsoncx_number */
        double valuedouble; /* the item's number, if type==jsoncx_number */

        char *string; /* the item's name string, if this item is the child of, or is in the list of subitems of an object. */
    } jsoncx;

    typedef struct jsoncx_hooks
    {
        void *(*malloc_fn)(size_t sz);
        void (*free_fn)(void *ptr);
    } jsoncx_hooks;

    /* supply malloc, realloc and free functions to jsoncx */
    extern void jsoncx_inithooks(jsoncx_hooks *hooks);

    /* supply a block of json, and this returns a jsoncx object you can interrogate. call jsoncx_delete when finished. */
    extern jsoncx *jsoncx_parse(const char *value);
    /* render a jsoncx entity to text for transfer/storage. free the char* when finished. */
    extern char *jsoncx_print(jsoncx *item);
    /* render a jsoncx entity to text for transfer/storage without any formatting. free the char* when finished. */
    extern char *jsoncx_printunformatted(jsoncx *item);
    /* render a jsoncx entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
    extern char *jsoncx_printbuffered(jsoncx *item, int prebuffer, int fmt);
    /* delete a jsoncx entity and all subentities. */
    extern void jsoncx_delete(jsoncx *c);

    /* returns the number of items in an array (or object). */
    extern int jsoncx_getarraysize(jsoncx *array);
    /* retrieve item number "item" from array "array". returns null if unsuccessful. */
    extern jsoncx *jsoncx_getarrayitem(jsoncx *array, int item);
    /* get item "string" from object. case insensitive. */
    extern jsoncx *jsoncx_getobjectitem(jsoncx *object, const char *string);

    /* for analysing failed parses. this returns a pointer to the parse error. you'll probably need to look a few chars back to make sense of it. defined when jsoncx_parse() returns 0. 0 when jsoncx_parse() succeeds. */
    extern const char *jsoncx_geterrorptr(void);

    /* these calls create a jsoncx item of the appropriate type. */
    extern jsoncx *jsoncx_createnull(void);
    extern jsoncx *jsoncx_createtrue(void);
    extern jsoncx *jsoncx_createfalse(void);
    extern jsoncx *jsoncx_createbool(int b);
    extern jsoncx *jsoncx_createnumber(double num);
    extern jsoncx *jsoncx_createstring(const char *string);
    extern jsoncx *jsoncx_createarray(void);
    extern jsoncx *jsoncx_createobject(void);

    /* these utilities create an array of count items. */
    extern jsoncx *jsoncx_createintarray(const int *numbers, int count);
    extern jsoncx *jsoncx_createfloatarray(const float *numbers, int count);
    extern jsoncx *jsoncx_createdoublearray(const double *numbers, int count);
    extern jsoncx *jsoncx_createstringarray(const char **strings, int count);

    /* append item to the specified array/object. */
    extern void jsoncx_additemtoarray(jsoncx *array, jsoncx *item);
    extern void jsoncx_additemtoobject(jsoncx *object, const char *string, jsoncx *item);
    extern void jsoncx_additemtoobjectcs(jsoncx *object, const char *string, jsoncx *item); /* use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the jsoncx object */
    /* append reference to item to the specified array/object. use this when you want to add an existing jsoncx to a new jsoncx, but don't want to corrupt your existing jsoncx. */
    extern void jsoncx_additemreferencetoarray(jsoncx *array, jsoncx *item);
    extern void jsoncx_additemreferencetoobject(jsoncx *object, const char *string, jsoncx *item);

    /* remove/detatch items from arrays/objects. */
    extern jsoncx *jsoncx_detachitemfromarray(jsoncx *array, int which);
    extern void jsoncx_deleteitemfromarray(jsoncx *array, int which);
    extern jsoncx *jsoncx_detachitemfromobject(jsoncx *object, const char *string);
    extern void jsoncx_deleteitemfromobject(jsoncx *object, const char *string);

    /* update array items. */
    extern void jsoncx_insertiteminarray(jsoncx *array, int which, jsoncx *newitem); /* shifts pre-existing items to the right. */
    extern void jsoncx_replaceiteminarray(jsoncx *array, int which, jsoncx *newitem);
    extern void jsoncx_replaceiteminobject(jsoncx *object, const char *string, jsoncx *newitem);

    /* duplicate a jsoncx item */
    extern jsoncx *jsoncx_duplicate(jsoncx *item, int recurse);
    /* duplicate will create a new, identical jsoncx item to the one you pass, in new memory that will
    need to be released. with recurse!=0, it will duplicate any children connected to the item.
    the item->next and ->prev pointers are always zero on return from duplicate. */

    /* parsewithopts allows you to require (and check) that the json is null terminated, and to retrieve the pointer to the final byte parsed. */
    extern jsoncx *jsoncx_parsewithopts(const char *value, const char **return_parse_end, int require_null_terminated);

    extern void jsoncx_minify(char *json);

/* macros for creating things quickly. */
#define jsoncx_addnulltoobject(object, name) jsoncx_additemtoobject(object, name, jsoncx_createnull())
#define jsoncx_addtruetoobject(object, name) jsoncx_additemtoobject(object, name, jsoncx_createtrue())
#define jsoncx_addfalsetoobject(object, name) jsoncx_additemtoobject(object, name, jsoncx_createfalse())
#define jsoncx_addbooltoobject(object, name, b) jsoncx_additemtoobject(object, name, jsoncx_createbool(b))
#define jsoncx_addnumbertoobject(object, name, n) jsoncx_additemtoobject(object, name, jsoncx_createnumber(n))
#define jsoncx_addstringtoobject(object, name, s) jsoncx_additemtoobject(object, name, jsoncx_createstring(s))

/* when assigning an integer value, it needs to be propagated to valuedouble too. */
#define jsoncx_setintvalue(object, val) ((object) ? (object)->valueint = (object)->valuedouble = (val) : (val))
#define jsoncx_setnumbervalue(object, val) ((object) ? (object)->valueint = (object)->valuedouble = (val) : (val))

#ifdef __cplusplus
}
#endif

#endif